#include <stdio.h>
#include <windows.h>
#include <time.h>
#include "lunar.h"
#include "calendar.h"
#include "festival.h"

// 设置控制台颜色（白底彩字）
void SetConsoleColor(WORD color) {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, color);
}

// 获取当前时间字符串
void GetCurTime(char *buf, int bufsize) {
    time_t t = time(NULL);
    struct tm *tm_info = localtime(&t);
    strftime(buf, bufsize, "%Y-%m-%d %H:%M:%S", tm_info);
}

// 计算字符串实际显示宽度（utf-8汉字宽2，英文宽1）
int GetDisplayWidth(const char* s) {
    int width = 0;
    while (*s) {
        unsigned char c = (unsigned char)*s;
        if (c >= 0x80) {
            // utf-8汉字3字节，宽度2
            if ((c & 0xE0) == 0xC0) { s += 2; } // 2字节utf-8
            else if ((c & 0xF0) == 0xE0) { s += 3; } // 3字节utf-8
            else { s++; } // 其他情况
            width += 2;
        } else {
            s++;
            width += 1;
        }
    }
    return width;
}

// 居中填充到8宽度（utf-8汉字宽2，英文宽1），pad用全角空格，强制每格8宽
void CenterPad8(const char* src, char* dst, int dstsize) {
    int width = GetDisplayWidth(src);
    int pad = 8 - width;
    int left = pad / 2;
    int right = pad - left;
    int pos = 0;
    // 全角空格utf-8编码
    const char* fullspace = "\xE3\x80\x80";
    for (int i = 0; i < left && pos < dstsize-1; ++i) {
        // pad用全角空格
        if (pos < dstsize-4) { memcpy(dst+pos, fullspace, 3); pos += 3; } else { dst[pos++] = ' '; }
    }
    for (const char* p = src; *p && pos < dstsize-1;) {
        unsigned char c = (unsigned char)*p;
        if (c >= 0x80) {
            if ((c & 0xE0) == 0xC0 && pos < dstsize-2) { dst[pos++] = *p++; dst[pos++] = *p++; }
            else if ((c & 0xF0) == 0xE0 && pos < dstsize-3) { dst[pos++] = *p++; dst[pos++] = *p++; dst[pos++] = *p++; }
            else { dst[pos++] = *p++; }
        } else {
            dst[pos++] = *p++;
        }
    }
    for (int i = 0; i < right && pos < dstsize-1; ++i) {
        if (pos < dstsize-4) { memcpy(dst+pos, fullspace, 3); pos += 3; } else { dst[pos++] = ' '; }
    }
    // 强制截断到8宽
    dst[pos] = 0;
    int realw = GetDisplayWidth(dst);
    while (realw > 8 && pos > 0) { dst[--pos] = 0; realw = GetDisplayWidth(dst); }
    // 若不足8宽，补空格
    while (realw < 8 && pos < dstsize-1) { dst[pos++] = ' '; dst[pos] = 0; realw = GetDisplayWidth(dst); }
}

// 统一的月历输出函数
void PrintFullMonthCalendar(int y, int m) {
    printf("\n      %d年%d月\n", y, m);
    // 星期标题行严格8宽居中
    const char* weekstr[7] = {"日","一","二","三","四","五","六"};
    for (int col = 0; col < 7; ++col) {
        char buf[17] = "";
        CenterPad8(weekstr[col], buf, sizeof(buf));
        printf("%s", buf);
    }
    printf("\n");
    int first_wday = GetWeekday(y, m, 1);
    int days = GetMonthDays(y, m);
    int week_start = 1;
    int is_first_row = 1;
    while (week_start <= days) {
        char gdays[7][17] = {""};
        char ldays[7][17] = {""};
        WORD gcolor[7] = {0};
        WORD lcolor[7] = {0};
        for (int col = 0; col < 7; ++col) {
            int dd = week_start + col - (week_start == 1 ? first_wday : 0);
            if ((week_start == 1 && col < first_wday) || dd < 1 || dd > days) {
                // 首行空白格只填7个空格，缓解右偏
                int pad = (week_start == 1) ? 7 : 8;
                for (int k = 0; k < pad; ++k) gdays[col][k] = ' ';
                gdays[col][pad] = 0;
                for (int k = 0; k < pad; ++k) ldays[col][k] = ' ';
                ldays[col][pad] = 0;
                gcolor[col] = 0x0F; lcolor[col] = 0x0F;
            } else {
                int tly, tlm, tld, tisLeap;
                SolarToLunar(y, m, dd, &tly, &tlm, &tld, &tisLeap);
                char tterm[16] = "";
                int isTermDay = GetSolarTerm(y, m, dd, tterm, sizeof(tterm));
                // 颜色控制
                if (isTermDay) {
                    gcolor[col] = 0x0A; // 绿字空白底
                    lcolor[col] = 0x0A;
                } else if (col == 0 || col == 6) {
                    gcolor[col] = 0x0C; // 红字
                    lcolor[col] = 0x0C;
                } else {
                    gcolor[col] = 0x0F; // 白字
                    lcolor[col] = 0x0F;
                }
                char numstr[8] = "";
                snprintf(numstr, sizeof(numstr), "%d", dd);
                CenterPad8(numstr, gdays[col], sizeof(gdays[col]));
                char lmonth[16] = "", lday[16] = "";
                LunarMonthToChinese(tlm, tisLeap, lmonth, sizeof(lmonth));
                LunarDayToChinese(tld, lday, sizeof(lday));
                char show[16] = "";
                if (isTermDay) {
                    snprintf(show, sizeof(show), "%s", tterm); // 只显示节气名
                } else if (tld == 1) {
                    snprintf(show, sizeof(show), "%s", lmonth);
                } else {
                    snprintf(show, sizeof(show), "%s", lday);
                }
                CenterPad8(show, ldays[col], sizeof(ldays[col]));
            }
        }
        // 输出一周的公历日
        for (int col = 0; col < 7; ++col) {
            SetConsoleColor(gcolor[col]);
            printf("%s", gdays[col]);
            SetConsoleColor(0x0F);
        }
        printf("\n");
        // 输出一周的农历日/节气
        for (int col = 0; col < 7; ++col) {
            SetConsoleColor(lcolor[col]);
            printf("%s", ldays[col]);
            SetConsoleColor(0x0F);
        }
        printf("\n");
        week_start += (week_start == 1 ? 7 - first_wday : 7);
        is_first_row = 0;
    }
    printf("注：周末红字，节气绿字，其余白字。农历注明闰月。\n");
}

// 主菜单显示
void ShowMenu() {
    SetConsoleColor(0xF4); // 白底红字
    printf("\n================ 超级万年历 ================\n");
    SetConsoleColor(0xF4); // 白底红字
    char curTime[32];
    GetCurTime(curTime, sizeof(curTime));
    printf("当前时间: %s\n", curTime);
    SetConsoleColor(0xF1); // 白底蓝字
    printf("1. 查询农历\n");
    printf("2. 查询公历\n");
    printf("3. 显示月历\n");
    printf("4. 查询某天距今天的天数\n");
    printf("5. 查询距今天相应天数的日期\n");
    printf("6. 查询任意两天之间的天数差\n");
    printf("7. 显示二十四节气\n");
    printf("8. 显示节日\n");
    printf("0. 退出程序\n");
    SetConsoleColor(0x0F); // 恢复默认
    printf("===========================================\n");
    printf("请输入功能编号: ");
}

// 主函数
int main() {
    int choice;
    while (1) {
        ShowMenu();
        if (scanf("%d", &choice) != 1) {
            while (getchar() != '\n'); // 清空输入缓冲区
            continue;
        }
        switch (choice) {
            case 1:
                // 查询农历功能
                {
                    int y, m, d;
                    printf("请输入公历日期（如2020 10 20）：");
                    if (scanf("%d %d %d", &y, &m, &d) == 3) {
                        // 公历日期范围校验
                        if (m < 1 || m > 12 || d < 1 || d > GetMonthDays(y, m)) {
                            printf("日期无效或超出范围！\n");
                            break;
                        }
                        int ly, lm, ld, isLeap;
                        if (SolarToLunar(y, m, d, &ly, &lm, &ld, &isLeap) == 0) {
                            char gz[32];
                            GetGanZhi(y, m, d, gz, sizeof(gz));
                            char term[16];
                            int isTerm = GetSolarTerm(y, m, d, term, sizeof(term));
                            // 1. 显示当月月历（和功能3一致）
                            PrintFullMonthCalendar(y, m);
                            // 输出该天农历信息
                            char lyear[32] = "", lmonth[16] = "", lday[16] = "";
                            LunarYearToChinese(ly, lyear, sizeof(lyear));
                            LunarMonthToChinese(lm, isLeap, lmonth, sizeof(lmonth));
                            LunarDayToChinese(ld, lday, sizeof(lday));
                            printf("%d-%d-%d 的农历是：%s%s%s\n", y, m, d, lyear, lmonth, lday);
                            // 2. 天干地支
                            printf("天干地支：%s\n", gz);
                            // 3. 节气信息
                            if (isTerm) {
                                printf("当天是节气：%s\n", term);
                            } else {
                                int nextTermDays = 0;
                                char nextTermName[16] = "";
                                int found = 0;
                                for (int add = 1; add <= 370; ++add) {
                                    int ty, tm, td;
                                    ty = y; tm = m; td = d + add;
                                    struct tm t = {0};
                                    t.tm_year = y - 1900;
                                    t.tm_mon = m - 1;
                                    t.tm_mday = d + add;
                                    mktime(&t);
                                    ty = t.tm_year + 1900;
                                    tm = t.tm_mon + 1;
                                    td = t.tm_mday;
                                    char tname[16] = "";
                                    if (GetSolarTerm(ty, tm, td, tname, sizeof(tname))) {
                                        nextTermDays = add;
                                        strncpy(nextTermName, tname, sizeof(nextTermName));
                                        found = 1;
                                        break;
                                    }
                                }
                                if (found) {
                                    printf("当天不是节气，距离下一个节气%s还有%d天\n", nextTermName, nextTermDays);
                                } else {
                                    printf("当天不是节气，且一年内无下一个节气（数据异常）\n");
                                }
                            }
                            // 4. 本月节气
                            int terms[2][2] = {0};
                            GetMonthSolarTerms(y, m, terms);
                            extern const char* SOLAR_TERMS[24];
                            printf("本月节气：");
                            for (int ti = 0; ti < 2; ++ti) {
                                if (terms[ti][0] > 0) {
                                    printf("%s%d日 ", SOLAR_TERMS[terms[ti][1]], terms[ti][0]);
                                }
                            }
                            printf("\n");
                        } else {
                            printf("日期无效或超出范围！\n");
                        }
                    } else {
                        printf("输入有误！\n");
                    }
                }
                break;
            case 2:
                // 查询公历功能
                {
                    int ly, lm, ld, isLeap;
                    printf("请输入农历日期（如2021 11 18），闰月输入1否则0：");
                    if (scanf("%d %d %d %d", &ly, &lm, &ld, &isLeap) == 4) {
                        // 农历日期范围校验（基本）
                        if (lm < 1 || lm > 12 || ld < 1 || ld > 30 || (isLeap != 0 && isLeap != 1)) {
                            printf("日期无效或超出范围！\n");
                            break;
                        }
                        int y, m, d;
                        if (LunarToSolar(ly, lm, ld, isLeap, &y, &m, &d) == 0) {
                            char gz[32];
                            GetGanZhi(y, m, d, gz, sizeof(gz));
                            char lyear[32] = "", lmonth[16] = "", lday[16] = "";
                            LunarYearToChinese(ly, lyear, sizeof(lyear));
                            LunarMonthToChinese(lm, isLeap, lmonth, sizeof(lmonth));
                            LunarDayToChinese(ld, lday, sizeof(lday));
                            printf("农历%s%s%s 对应的公历日期是：%d-%d-%d\n", lyear, lmonth, lday, y, m, d);
                            printf("天干地支：%s\n", gz);
                        } else {
                            printf("日期无效或超出范围！\n");
                        }
                    } else {
                        printf("输入有误！\n");
                    }
                }
                break;
            case 3:
                // 显示月历功能
                {
                    int y, m;
                    printf("请输入年份和月份（如2021 11）：");
                    if (scanf("%d %d", &y, &m) == 2 && y >= 1900 && m >= 1 && m <= 12) {
                        PrintFullMonthCalendar(y, m);
                    } else {
                        printf("输入有误！\n");
                    }
                }
                break;
            case 4:
                // 查询某天距今天的天数
                {
                    int y, m, d;
                    printf("请输入要查询的日期（如2020 11 3）：");
                    if (scanf("%d %d %d", &y, &m, &d) == 3) {
                        time_t now = time(NULL);
                        struct tm *tm_now = localtime(&now);
                        int today_y = tm_now->tm_year + 1900;
                        int today_m = tm_now->tm_mon + 1;
                        int today_d = tm_now->tm_mday;
                        int diff = DaysBetween(y, m, d, today_y, today_m, today_d);
                        if (diff == 0) {
                            printf("%d-%d-%d 就是今天！\n", y, m, d);
                        } else if (diff > 0) {
                            printf("%d-%d-%d 比今天（%d-%d-%d）早【%d】天\n", y, m, d, today_y, today_m, today_d, diff);
                        } else {
                            printf("%d-%d-%d 比今天（%d-%d-%d）晚【%d】天\n", y, m, d, today_y, today_m, today_d, -diff);
                        }
                    } else {
                        printf("输入有误！\n");
                    }
                }
                break;
            case 5:
                // 查询距今天相应天数的日期
                {
                    int n;
                    printf("请输入天数：");
                    if (scanf("%d", &n) == 1) {
                        time_t now = time(NULL);
                        struct tm *tm_now = localtime(&now);
                        int today_y = tm_now->tm_year + 1900;
                        int today_m = tm_now->tm_mon + 1;
                        int today_d = tm_now->tm_mday;
                        int ry1, rm1, rd1, ry2, rm2, rd2;
                        AddDays(today_y, today_m, today_d, -n, &ry1, &rm1, &rd1);
                        AddDays(today_y, today_m, today_d, n, &ry2, &rm2, &rd2);
                        int w1 = GetWeekday(ry1, rm1, rd1);
                        int w2 = GetWeekday(ry2, rm2, rd2);
                        const char* weekstr[] = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
                        printf("距离今天（%d-%d-%d）早%d天的日期为：%d年%d月%d日 %s\n", today_y, today_m, today_d, n, ry1, rm1, rd1, weekstr[w1]);
                        printf("距离今天（%d-%d-%d）晚%d天的日期为：%d年%d月%d日 %s\n", today_y, today_m, today_d, n, ry2, rm2, rd2, weekstr[w2]);
                    } else {
                        printf("输入有误！\n");
                    }
                }
                break;
            case 6:
                // 查询任意两天之间的天数差
                {
                    int y1, m1, d1, y2, m2, d2;
                    printf("请输入第一个日期（如2020 11 3）：");
                    if (scanf("%d %d %d", &y1, &m1, &d1) == 3) {
                        printf("请输入第二个日期（如2021 11 15）：");
                        if (scanf("%d %d %d", &y2, &m2, &d2) == 3) {
                            int diff = DaysBetween(y1, m1, d1, y2, m2, d2);
                            printf("%d-%d-%d 与 %d-%d-%d 相差【%d】天\n", y1, m1, d1, y2, m2, d2, diff >= 0 ? diff : -diff);
                        } else {
                            printf("输入有误！\n");
                        }
                    } else {
                        printf("输入有误！\n");
                    }
                }
                break;
            case 7:
                // 显示二十四节气
                {
                    int y;
                    printf("请输入年份：");
                    if (scanf("%d", &y) == 1 && y >= 1901 && y <= 2100) {
                        // 正确的节气顺序下标
                        static const int MONTH_SOLAR_TERM_INDEX[12][2] = {
                            {0, 1},    // 1月: 小寒, 大寒
                            {2, 3},    // 2月: 立春, 雨水
                            {4, 5},    // 3月: 惊蛰, 春分
                            {6, 7},    // 4月: 清明, 谷雨
                            {8, 9},    // 5月: 立夏, 小满
                            {10, 11},  // 6月: 芒种, 夏至
                            {12, 13},  // 7月: 小暑, 大暑
                            {14, 15},  // 8月: 立秋, 处暑
                            {16, 17},  // 9月: 白露, 秋分
                            {18, 19},  // 10月: 寒露, 霜降
                            {20, 21},  // 11月: 立冬, 小雪
                            {22, 23}   // 12月: 大雪, 冬至
                        };
                        extern const char* SOLAR_TERMS[24];
                        printf("%d年二十四节气：\n", y);
                        for (int m = 1; m <= 12; ++m) {
                            int idx1 = MONTH_SOLAR_TERM_INDEX[m-1][0];
                            int idx2 = MONTH_SOLAR_TERM_INDEX[m-1][1];
                            SolarTermDate t1 = get_solar_term_date(y, idx1);
                            SolarTermDate t2 = get_solar_term_date(y, idx2);
                            // DEBUG: 打印查表原始日
                            extern const SolarTermDate solar_terms_table[200][24];
                            // printf("DEBUG: %d年 %s 查表原始日=%d\n", y, SOLAR_TERMS[idx1], solar_terms_table[y-1901+1][idx1].day);
                            printf("%2d月: %s%d日, %s%d日\n", m,
                                SOLAR_TERMS[idx1], t1.day,
                                SOLAR_TERMS[idx2], t2.day);
                        }
                    } else {
                        printf("输入有误！\n");
                    }
                }
                break;
            case 8:
                // 显示节日
                {
                    int sub;
                    printf("1. 显示公历节日\n2. 显示农历节日\n请选择: ");
                    scanf("%d", &sub);
                    if (sub == 1) {
                        int month;
                        printf("请输入要查询的月份: ");
                        scanf("%d", &month);
                        if (month >= 1 && month <= 12) {
                            ShowSolarFestivalsOfMonth(month);
                        } else {
                            printf("月份输入有误！\n");
                        }
                    } else if (sub == 2) {
                        ShowAllLunarFestivals();
                    } else {
                        printf("无效选项！\n");
                    }
                }
                break;
            case 0:
                printf("感谢使用超级万年历！\n");
                return 0;
            default:
                printf("无效的选项，请重新输入！\n");
                break;
        }
        printf("\n按回车键继续...");
        getchar();
        getchar();
    }
    return 0;
}
